/** @file bt_tx.c
  *
  * @brief This file contains the TX handling functions 
  * of Bluetooth driver.
  * 
  * (c) Copyright 2003-2007, Marvell International Ltd.
  * All Rights Reserved
  */

#include <windows.h>

#include "bt_def.h"
#include "bt_dev.h"
#include "bt_func.h"
#include "igxBug.h"


/********************************************************
        Local Variables
********************************************************/

/********************************************************
        Global Variables
********************************************************/

/********************************************************
        Local Functions
********************************************************/

/********************************************************
        Global Functions
********************************************************/
MRVL_STATUS SendSinglePacket(PUCHAR buf,
                             ULONG bufLen)
{
    SD_TRANSPORT_HEADER *header;
    SD_API_STATUS       Status;
    MRVL_STATUS         ret = MRVL_STATUS_SUCCESS;
    DWORD waitStatus;

    header = (SD_TRANSPORT_HEADER *)buf;

    DBGPRINT(DBG_TX, (L"++SendSinglePacket++\n\r"));

    if (Adapter->CardRemoved == TRUE)
    {
        DBGPRINT(DBG_TX|DBG_ERROR, (L"SDIO Card Removed !\n\r"));
        ret = MRVL_STATUS_FAILURE;
        goto exit;
    }

#if 1
    /* 2007-11-20
     * If we ignore the PS state checking and send down packet directly,
     * firmware still can receive it because interface is active now 
     * due to WLAN function is active.
     * But driver has to do this checking for logical reason.
     */
    if (Adapter->ps_state == PS_SLEEP)
    {
        DBGPRINT(DBG_TX|DBG_PS|DBG_WARNING, (L"Tx Packet in PS_SLEEP !\n\r"));

        /* Power Up Device, will receive PS_AWAKE Event from firmware */
        Status = If_PowerUpDevice(Adapter, BT_FUNC);
        if (!SD_API_SUCCESS(Status))
        {
            DBGPRINT(DBG_TX|DBG_PS|DBG_ERROR, (L"Power Up Device Fail !\n\r"));
            ret = MRVL_STATUS_FAILURE;
            goto exit;
        }
        else
        {
            DBGPRINT(DBG_TX|DBG_PS, (L"Power Up Device OK !\n\r"));
        }

        DBGPRINT(DBG_PS, (L"Wait for PS_AWAKE event ..... \n\r"));
        waitStatus = WaitForSingleObject(Adapter->hPSAwakeEvent, WAIT_PS_AWAKE_TIMEOUT);
        switch (waitStatus)
        {
            case WAIT_OBJECT_0:
                DBGPRINT(DBG_PS, (L"PS_AWAKE event received.\n\r"));
                break;
            case WAIT_TIMEOUT:
                DBGPRINT(DBG_PS|DBG_ERROR, (L"Wait PS_AWAKE event timeout !\n\r"));
                ret = MRVL_STATUS_FAILURE;
                goto exit;
        }
    }
#endif

    if (!bufLen || (bufLen > BT_UPLD_SIZE))
    {
        DBGPRINT(DBG_TX|DBG_ERROR, (L"Tx Error: %d : %d\n\r", bufLen, BT_UPLD_SIZE));
        ret = MRVL_STATUS_FAILURE;
        goto exit;
    } 

    EnterCriticalSection(&Adapter->TxCriticalSection);

    /*  This is SDIO specific header
     *  length: byte[3][2][1], 
     *  type: byte[0] (HCI_COMMAND = 1, ACL_DATA = 2, SCO_DATA = 3, 0xFE = Vendor) 
     */
    Adapter->TmpTxBuf[0] = (UCHAR)bufLen & 0xff;
    Adapter->TmpTxBuf[1] = (UCHAR)(bufLen >> 8) & 0xff;
    Adapter->TmpTxBuf[2] = (UCHAR)(bufLen >> 16) & 0xff;
    Adapter->TmpTxBuf[3] = (UCHAR)header->u.AsUCHAR.ServiceID;

    memmove(&Adapter->TmpTxBuf[SDIO_HEADER_LEN],
            buf+SDIO_HEADER_LEN,
            bufLen-SDIO_HEADER_LEN);

    HexDump(DBG_TX_DUMP, "Tx BUFFER: ", Adapter->TmpTxBuf, bufLen);

    Status = If_DownloadPkt(Adapter, BT_FUNC, Adapter->TmpTxBuf, bufLen);
    if (!SD_API_SUCCESS(Status))
    {
        DBGPRINT(DBG_TX, (L"Download SDIO Packet Fail !\n\r"));
        ret = MRVL_STATUS_FAILURE;
    }
    else
    {
        ret = MRVL_STATUS_SUCCESS;
    }

    LeaveCriticalSection(&Adapter->TxCriticalSection);

exit:
    return ret;
}
